using Godot;
using System;
using System.Linq;
using System.Collections.Generic;
using Common;

namespace Library {
	public class SpriteCollectionEditor : Control {
		#region Nodes
		FileDialog fileDialog;
		AcceptDialog acceptDialog;
		ItemList groupList;
		ConfirmationDialog spritesEditDialog;
		TextEdit spritesEdit;

		ItemList spritesList;
		LineEdit startIndex;
		LineEdit speed;
		CheckBox startPlaying;
		CheckBox looped;
		CheckBox flipX;
		CheckBox flipY;
		CheckBox centered;
		LineEdit originX;
		LineEdit originY;
		LineEdit groupWhenEnd;

		LineEdit collectionName;
		LineEdit groupName;
		#endregion
		enum FileDialogMode {
			OpenSprites,
			OpenCollection,
			SaveCollection
		}
		FileDialogMode currentFileDialogMode;
		public override void _Ready() {
			fileDialog = GetNode<FileDialog>("FileDialog");
			acceptDialog = GetNode<AcceptDialog>("AcceptDialog");
			spritesEditDialog = GetNode<ConfirmationDialog>("SpritesEditDialog");
			spritesEdit = GetNode<TextEdit>("SpritesEditDialog/TextEdit");
			groupList = GetNode<ItemList>("Main/Collections/VBoxContainer/GroupList");
			spritesList = GetNode<ItemList>("Main/Arguments/ScrollContainer/GridContainer/SpritesList");
			startIndex = GetNode<LineEdit>("Main/Arguments/ScrollContainer/GridContainer/StartIndexEdit");
			speed = GetNode<LineEdit>("Main/Arguments/ScrollContainer/GridContainer/SpeedEdit");
			startPlaying = GetNode<CheckBox>("Main/Arguments/ScrollContainer/GridContainer/Flags/StartPlaying");
			looped = GetNode<CheckBox>("Main/Arguments/ScrollContainer/GridContainer/Flags/Looped");
			flipX = GetNode<CheckBox>("Main/Arguments/ScrollContainer/GridContainer/Flags/FlipX");
			flipY = GetNode<CheckBox>("Main/Arguments/ScrollContainer/GridContainer/Flags/FlipY");
			centered = GetNode<CheckBox>("Main/Arguments/ScrollContainer/GridContainer/Flags/Centered");
			originX = GetNode<LineEdit>("Main/Arguments/ScrollContainer/GridContainer/OriginContainer/EditX");
			originY = GetNode<LineEdit>("Main/Arguments/ScrollContainer/GridContainer/OriginContainer/EditY");
			groupWhenEnd = GetNode<LineEdit>("Main/Arguments/ScrollContainer/GridContainer/GroupWhenEndEdit");

			collectionName = GetNode<LineEdit>("Main/Collections/VBoxContainer/CollectionBar/CollectionName");
			groupName = GetNode<LineEdit>("Main/Collections/VBoxContainer/GroupBar/GroupName");

			OnNewCollectionPressed();
		}

		SpriteController.Collection collection;

		string selectedGroup = "";




		void ShowFileDialog(FileDialogMode mode) {
			currentFileDialogMode = mode;
			switch (mode) {
				case FileDialogMode.OpenSprites:
					fileDialog.Mode = FileDialog.ModeEnum.OpenFiles;
					fileDialog.WindowTitle = "Open Sprites";
					fileDialog.Filters = new string[1] { "*.png ; Sprite" };
					break;
				case FileDialogMode.OpenCollection:
					fileDialog.Mode = FileDialog.ModeEnum.OpenFile;
					fileDialog.WindowTitle = "Open Collection";
					fileDialog.Filters = new string[1] { "*.json ; Collection" };
					break;
				case FileDialogMode.SaveCollection:
					fileDialog.Mode = FileDialog.ModeEnum.SaveFile;
					fileDialog.WindowTitle = "Save Collection";
					fileDialog.Filters = new string[1] { "*.json ; Collection" };
					break;
			}
			fileDialog.PopupCentered();
		}

		void ShowAcceptDialog(string text) {
			acceptDialog.DialogText = text;
			acceptDialog.PopupCentered();
		}
		void OnOpenCollectionsPressed() {
			ShowFileDialog(FileDialogMode.OpenCollection);
		}
		void OnSaveSelectedCollectionPressed() {
			ShowFileDialog(FileDialogMode.SaveCollection);
		}
		void OnOpenSpritesPressed() {
			ShowFileDialog(FileDialogMode.OpenSprites);
		}

		private void OnFileDialogFileSelected(string path) {
			if (currentFileDialogMode == FileDialogMode.OpenCollection) {
				JsonFile<SpriteController.Collection> json = new JsonFile<SpriteController.Collection>(path);
				collection = json.Source;
				groupList.Clear();
				foreach (string key in collection.Groups.Keys) {
					groupList.AddItem(key);
				}
				collectionName.Text = collection.Name;
			} else if (currentFileDialogMode == FileDialogMode.SaveCollection) {
				JsonFile<SpriteController.Collection> json = new JsonFile<SpriteController.Collection>(path);
				json.Source = collection;
				json.Save();
			}
		}
		private void OnFileDialogFilesSelected(string[] paths) {
			foreach (string path in paths) {
				spritesList.AddItem(path);
			}
		}

		private void OnNewCollectionPressed() {
			collection = new SpriteController.Collection();
			collectionName.Text = "NewCollection";
			collection.Name = "NewCollection";
			groupList.Clear();
		}

		void OnRemoveSpritesPressed() {
			foreach (int id in spritesList.GetSelectedItems().OrderByDescending(x => x)) {
				spritesList.RemoveItem(id);
			}
		}
		void OnEditSpritePressed() {
			string text = "";
			for (int i = 0; i < spritesList.GetItemCount(); i += 1) {
				text += spritesList.GetItemText(i) + "\n";
			}
			text = text.Trim();
			spritesEdit.Text = text;
			spritesEditDialog.PopupCentered();
		}
		private void OnSpritesEditDialogConfirmed() {
			string text = spritesEdit.Text.Trim();
			string[] texts = text.Split('\n');
			spritesList.Clear();
			foreach (string sprite in texts) {
				if (!string.IsNullOrWhiteSpace(sprite)) {
					spritesList.AddItem(sprite);
				}
			}
		}
		private void OnAddGroupPressed() {
			int append = 0;
			const string defaultName = "NewGroup_";
			while (IsGroupExists(defaultName + append)) {
				append += 1;
			}
			AddGroup(defaultName + append);
		}
		private void OnRemoveGroupPressed() {
			if (groupList.GetSelectedItems().Length <= 0) {
				return;
			}
			string key = groupList.GetItemText(groupList.GetSelectedItems()[0]);
			RemoveGroup(key);
		}
		private void OnGroupNameEditEntered(string text) {
			if (groupList.GetSelectedItems().Length <= 0) {
				return;
			}
			if (string.IsNullOrWhiteSpace(text) || collection.Groups.ContainsKey(text)) {
				return;
			}
			string key = groupList.GetItemText(groupList.GetSelectedItems()[0]);
			RenameGroup(key, text);
		}
		private void OnSaveGroupPressed() {
			if (groupList.GetSelectedItems().Length <= 0) {
				return;
			}
			string key = groupList.GetItemText(groupList.GetSelectedItems()[0]);
			SpriteController.Group group = GetGroup(key);
			group.Centered = centered.Pressed;
			group.FlipX = flipX.Pressed;
			group.FlipY = flipY.Pressed;
			group.GroupWhenEnd = groupWhenEnd.Text;
			group.Looped = looped.Pressed;
			List<string> sprites=new List<string>();
			for (int i = 0; i < spritesList.GetItemCount(); i += 1) {
				sprites.Add(spritesList.GetItemText(i));
			}
			group.Sprites = sprites.ToArray();
			group.StartPlaying = startPlaying.Pressed;
			try {
				group.Origin=new Vector2(float.Parse(originX.Text),float.Parse(originY.Text));
				group.Speed = float.Parse(speed.Text);
				group.StartIndex = float.Parse(startIndex.Text);
			} catch (FormatException) {
				ShowAcceptDialog("Error: Cannot parse the string!");
			}
		}
		private void OnGroupChanged(int id) {
			string key = groupList.GetItemText(id);
			groupName.Text = key;
			SpriteController.Group group = GetGroup(key);
			centered.Pressed = group.Centered;
			flipX.Pressed = group.FlipX;
			flipY.Pressed = group.FlipY;
			groupWhenEnd.Text = group.GroupWhenEnd;
			looped.Pressed = group.Looped;
			originX.Text = group.Origin.x.ToString();
			originY.Text = group.Origin.y.ToString();
			speed.Text = group.Speed.ToString();
			spritesList.Clear();

			foreach (string sprite in group.Sprites) {
				spritesList.AddItem(sprite);
			}
			startIndex.Text = group.StartIndex.ToString();
			startPlaying.Pressed = group.StartPlaying;
		}
		private void OnCollectionNameEntered(String new_text) {
			collection.Name = new_text;
		}

		bool AddGroup(string name) {
			if (IsGroupExists(name)) {
				return false;
			}
			collection.Groups.Add(name, new SpriteController.Group());
			groupList.AddItem(name);
			return true;
		}
		bool IsGroupExists(string name) => collection.Groups.ContainsKey(name);
		SpriteController.Group GetGroup(string name) => IsGroupExists(name) ? collection.Groups[name] : null;
		bool RenameGroup(string originalName, string newName) {
			if (!IsGroupExists(originalName) || IsGroupExists(newName)) {
				return false;
			}
			SpriteController.Group group = GetGroup(originalName);
			collection.Groups.Remove(originalName);
			collection.Groups.Add(newName, group);
			groupList.SetItemText(GetListIndex(originalName), newName);
			return true;
		}
		int GetListIndex(string name) {
			int i = 0;
			for (i = 0; i < groupList.GetItemCount(); i += 1) {
				if (groupList.GetItemText(i) == name) {
					return i;
				}
			}
			return -1;
		}
		bool RemoveGroup(string name) {
			if (!IsGroupExists(name)) {
				return false;
			}
			collection.Groups.Remove(name);
			groupList.RemoveItem(GetListIndex(name));
			return true;
		}
		//bool SelectGroup(string name)
	}
}
